package model;

import enums.ExtensionEnum;
import enums.PremisaTypeEnum;
import enums.VennEnum;
/*

    This file is part of Logica-Logike.

    Logica-Logike is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation version 3 of the License.

    Logica-Logike is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Logica-Logike.  If not, see <http://www.gnu.org/licenses/>.

 */
/**
 * Modela los diagramas de Venn;
 *
 * @author Jose Martin Rozanec;
 */
public class Venn {
    /**
     * Realiza el analisis del silogismo a partir de la teoria de los diagramas de Venn;
     *
     * @param sylogism;
     * @return VennEnum[];
     */
    public static VennEnum[] analizeSylogism(Sylogism sylogism) {
        VennEnum[] vennEnums = new VennEnum[7];
        for (int j = 0; j < vennEnums.length; j++) {
            vennEnums[j] = VennEnum.NOTHING;
        }
        if (sylogism.isComplete()) {
            switch (sylogism.getFigure()) {
                case FIRST:
                    firstPremisaFigures1And3(vennEnums, sylogism.getPremisa(PremisaTypeEnum.FIRST).getPartsExtension());
                    secondPremisaFigures1And2(vennEnums, sylogism.getPremisa(PremisaTypeEnum.SECOND).getPartsExtension());
                    break;
                case SECOND:
                    firstPremisaFigures2And4(vennEnums, sylogism.getPremisa(PremisaTypeEnum.FIRST).getPartsExtension());
                    secondPremisaFigures1And2(vennEnums, sylogism.getPremisa(PremisaTypeEnum.SECOND).getPartsExtension());
                    break;
                case THIRD:
                    firstPremisaFigures1And3(vennEnums, sylogism.getPremisa(PremisaTypeEnum.FIRST).getPartsExtension());
                    secondPremisaFigures3And4(vennEnums, sylogism.getPremisa(PremisaTypeEnum.SECOND).getPartsExtension());
                    break;
                case FOURTH:
                    firstPremisaFigures2And4(vennEnums, sylogism.getPremisa(PremisaTypeEnum.FIRST).getPartsExtension());
                    secondPremisaFigures3And4(vennEnums, sylogism.getPremisa(PremisaTypeEnum.SECOND).getPartsExtension());
                    break;
            }
        }
        return vennEnums;
    }

    /**
     * El metodo permite comparar una solucion provista con la resolucion del silogismo,
     * para conocer si la solucion es correcta;
     *
     * @param solution - VennEnum[];
     * @param sylogism - Sylogism;
     * @return boolean;
     */
    public static boolean isCorrect(VennEnum[] solution, Sylogism sylogism) {
        VennEnum[] realSolution = analizeSylogism(sylogism);
        for (int j = 0; j < realSolution.length; j++) {
            if (solution[j] != realSolution[j]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Metodo auxiliar para el analisis de Venn;
     *
     * @param vennEnums;
     * @param extensionEnum;
     */
    private static void firstPremisaFigures2And4(VennEnum[] vennEnums, ExtensionEnum extensionEnum) {
        switch (extensionEnum) {
            case A:
                vennEnums[0] = VennEnum.FILL;
                vennEnums[3] = VennEnum.FILL;
                break;
            case E:
                vennEnums[1] = VennEnum.FILL;
                vennEnums[4] = VennEnum.FILL;
                break;
            case I:
                vennEnums[1] = VennEnum.CROSS;
                vennEnums[4] = VennEnum.CROSS;
                break;
            case O:
                vennEnums[0] = VennEnum.CROSS;
                break;
        }
    }

    /**
     * Metodo auxiliar para el analisis de Venn;
     *
     * @param vennEnums;
     * @param extensionEnum;
     */
    private static void firstPremisaFigures1And3(VennEnum[] vennEnums, ExtensionEnum extensionEnum) {
        switch (extensionEnum) {
            case A:
                vennEnums[2] = VennEnum.FILL;
                vennEnums[5] = VennEnum.FILL;
                break;
            case E:
                vennEnums[1] = VennEnum.FILL;
                vennEnums[4] = VennEnum.FILL;
                break;
            case I:
                vennEnums[1] = VennEnum.CROSS;
                vennEnums[4] = VennEnum.CROSS;
                break;
            case O:
                vennEnums[2] = VennEnum.CROSS;
                vennEnums[5] = VennEnum.CROSS;
                break;
        }
    }

    /**
     * Metodo auxiliar para el analisis de Venn;
     *
     * @param vennEnums;
     * @param extensionEnum;
     */
    private static void secondPremisaFigures1And2(VennEnum[] vennEnums, ExtensionEnum extensionEnum) {
        switch (extensionEnum) {
            case A:
                vennEnums[3] = VennEnum.FILL;
                vennEnums[6] = VennEnum.FILL;
                break;
            case E:
                vennEnums[4] = VennEnum.FILL;
                vennEnums[5] = VennEnum.FILL;
                break;
            case I:
                if (vennEnums[4] != null && vennEnums[4] != VennEnum.FILL) {
                    vennEnums[4] = VennEnum.CROSS;
                }
                if (vennEnums[5] != null && vennEnums[5] != VennEnum.FILL) {
                    vennEnums[5] = VennEnum.CROSS;
                }
                break;
            case O:
                if (vennEnums[3] != null && vennEnums[3] != VennEnum.FILL) {
                    vennEnums[3] = VennEnum.CROSS;
                }
                if (vennEnums[6] != null && vennEnums[6] != VennEnum.FILL) {
                    vennEnums[6] = VennEnum.CROSS;
                }
                break;
        }
    }

    /**
     * Metodo auxiliar para el analisis de Venn;
     *
     * @param vennEnums;
     * @param extensionEnum;
     */
    private static void secondPremisaFigures3And4(VennEnum[] vennEnums, ExtensionEnum extensionEnum) {
        switch (extensionEnum) {
            case A:
                vennEnums[1] = VennEnum.FILL;
                vennEnums[2] = VennEnum.FILL;
                break;
            case E:
                vennEnums[4] = VennEnum.FILL;
                vennEnums[5] = VennEnum.FILL;
                break;
            case I:
                if (vennEnums[4] != null && vennEnums[4] != VennEnum.FILL) {
                    vennEnums[4] = VennEnum.CROSS;
                }
                if (vennEnums[5] != null && vennEnums[5] != VennEnum.FILL) {
                    vennEnums[5] = VennEnum.CROSS;
                }
                break;
            case O:
                if (vennEnums[1] != null && vennEnums[1] != VennEnum.FILL) {
                    vennEnums[1] = VennEnum.CROSS;
                }
                if (vennEnums[2] != null && vennEnums[2] != VennEnum.FILL) {
                    vennEnums[2] = VennEnum.CROSS;
                }
                break;
        }
    }

    /**
     * Devuelve la representacion XML del diagrama de Venn;
     *
     * @param sylogism;
     * @param vennEnums;
     * @return String;
     */
    public static String toXML(Sylogism sylogism, VennEnum[] vennEnums) {
        StringBuffer xmlExpression = new StringBuffer();
        xmlExpression.append(openTag());
        xmlExpression.append("<venn-sylogism>");
        xmlExpression.append(sylogism.toXML());
        xmlExpression.append("</venn-sylogism>");
        for (int j = 0; j < vennEnums.length; j++) {
            xmlExpression.append("<venn-enum>");
            xmlExpression.append(vennEnums[j].toString());
            xmlExpression.append("</venn-enum>");
        }
        xmlExpression.append(closeTag());
        return xmlExpression.toString();
    }

    /**
     * Interpreta el XML y devuelve el silogismo contenido en el diagrama de Venn;
     *
     * @param xml;
     * @return Sylogism;
     */
    public static Sylogism sylogismFromXML(String xml) {
        xml = xml.replace(openTag(), "");
        xml = xml.replace("<venn-sylogism>", "");
        return Sylogism.parseXML(xml.split("</venn-sylogism>")[0]);
    }

    /**
     * Obtiene los valores del diagrama de Venn a partir del XML;
     *
     * @param xml;
     * @return VennEnum[];
     */
    public static VennEnum[] vennEnumsFromXML(String xml) {
        xml = xml.split("</venn-sylogism>")[1];
        xml = xml.replace(closeTag(), "");
        xml = xml.replace("<venn-enum>", "");
        String[] values = xml.split("</venn-enum>");
        VennEnum[] vennEnums = new VennEnum[values.length];
        for (int j = 0; j < values.length; j++) {
            vennEnums[j] = VennEnum.valueOf(values[j]);
        }
        return vennEnums;
    }

    /**
     * Provee un arreglo de VenEnum por defecto;
     *
     * @return VennEnum[];
     */
    public static VennEnum[] getDefaultVennRepresentation() {
        VennEnum[] defaultArray = new VennEnum[7];
        for (int j = 0; j < 7; j++) {
            defaultArray[j] = VennEnum.NOTHING;
        }
        return defaultArray;
    }

    /**
     * Devuelve el tag de apertura de la representacion XML del diagrama de Venn;
     *
     * @return String;
     */
    public static String openTag() {
        return "<venn>";
    }

    /**
     * Devuelve el tag de clausura de la representacion XML del diagrama de Venn;
     *
     * @return String;
     */
    public static String closeTag() {
        return "</venn>";
    }
}
